package data;

import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Date;
import java.util.TreeSet;


import logic.MovieDefaltComparator;

//import com.sun.tools.javac.code.Attribute.Array;

/**
 * describes a User record
 * @author the secret 4 and the dog
 *
 */
public class UserTuple implements Comparator<RatingTuple>{
	private String _name;
	private String _password;
	private String _bdate;
	private boolean _sex; //female - true , male - false
	private String _type;
	private TreeSet<RatingTuple> _ratings;
	private double avg ;
	private MovieComputedRating[] _moviesRecomended;
	private Date dateOfRecs;

	/**
	 * creates a new instance of UserTuple
	 * @param name
	 * @param pw
	 * @param sex
	 * @param bdate
	 * @param type
	 */
	/*
	public UserTuple(String name, String pw, String sex, String bdate, String type) {
		_name = name;
		_password = pw;
		_sex = Boolean.parseBoolean(sex);
		_bdate = bdate;
		_type = type;
		_ratings = new TreeSet<RatingTuple>(new CompartorMovie());//(new MovieTuple("","","","","","","",""));
		avg= 0;
		_loggedIn = false;

	}
*/
	/**
	 * ONLY SYSTEM DATA SHUOLD USE THIS
	 */
	public UserTuple(String name, String pw, String sex, String bdate, String type) {
		_name = name;
		_password = pw;
		System.out.println(sex);
		_sex = Boolean.parseBoolean(sex);
		System.out.println("created user sex is " + _sex );
		_bdate = bdate;
		_type = type;
		//_ratings = new TreeSet<RatingTuple>(new CompartorMovie());//(new MovieTuple("","","","","","","",""));
		_ratings=null;
		avg= 0;		
	}


	
	public void addRating(RatingTuple rating){
		calcNewAvg(rating);
		if(_ratings!=null)
			_ratings.add(rating);

	}

	private void calcNewAvg(RatingTuple rating) {
		if(_ratings==null)
			getRatings();
		double size=_ratings.size();
		avg= (avg*size+rating.get_rating())/(size+1) ;
		
		//TODO maybe need to rewrite this to sql via system data
		
	}

	public boolean equals(Object other){
		boolean ans =true;
		if (!((UserTuple)other)._name.equals(this._name)){
			ans=false;
		}
		return ans;
	}

	public int compare(RatingTuple o1 , RatingTuple o2) {
		return o1.get_user()._name.compareTo(o2.get_user()._name);
	}

	public String getKey(){
		return _name;
	}
	public boolean isPassword(String pass){
		try {
			return encrypt(pass).equals(_password);
		} catch (NoSuchAlgorithmException e) {
			return false;
		}
	}
	public String get_name() {
		return _name;
	}
	
	public String get_password() {
		return _password;
	}
	

	public String get_bdate() {
		return _bdate;
	}

	public boolean is_sex() {
		return _sex;
	}

	public String get_type() {
		return _type;
	}


	private String encrypt(String x) throws NoSuchAlgorithmException  // throws Exception
	{
		java.security.MessageDigest d =null;
		d = java.security.MessageDigest.getInstance("SHA-1");
		d.reset();
		d.update(x.getBytes());
		return  byteArrayToHexString(d.digest());
	  }
	
	private String byteArrayToHexString(byte[] b){
	    StringBuffer sb = new StringBuffer(b.length * 2);
	    for (int i = 0; i < b.length; i++){
	      int v = b[i] & 0xff;
	      if (v < 16) {
	        sb.append('0');
	      }
	      sb.append(Integer.toHexString(v));
	    }
	    return sb.toString().toUpperCase();
	}


	public double getAvg(){
		return avg;
	}
	public TreeSet<RatingTuple>  getRatings(){
		if (_ratings==null)
			_ratings=SystemData.getInstance().getRatingsByUser(_name);
		return _ratings;
	}

	public boolean isAdmin(){
		//return _type.equals("admin"); why do we need adminTuple if we have a type???
		return false;
	}

	public void removeRating(RatingTuple rating) {
		if (_ratings!=null)
			_ratings.remove(rating);

	}

	public TreeSet<RatingTuple> getCopyOfRatings() {
		if (_ratings==null)
			getRatings();
		return (new TreeSet<RatingTuple>(_ratings));
		
	}

	public void setRecs(MovieComputedRating[] movies) {
		_moviesRecomended=movies;
	}
	
	public MovieComputedRating[] getRecs(int begin){

		if (begin> _moviesRecomended.length)
			return null;
		int tmpsize=_moviesRecomended.length-begin;
		if (tmpsize>10)
			tmpsize=10;
		MovieComputedRating[] recs = new MovieComputedRating[tmpsize];
		for (int i =0 ;i< tmpsize ;i++){
			recs[i]=_moviesRecomended[begin+i];
		}
		return recs;

	}

	public Date getDateOfRecs() {
		return dateOfRecs;
	}

	public void setDateOfRecs() {
		this.dateOfRecs = new Date();
	}


	public boolean hasSeenMovie(RatingTuple ratingTuple) {
		if (_ratings==null)
			getRatings();
		return _ratings.contains(ratingTuple);
	}

	public boolean hasSeenMovie(MovieTuple movie) {
		if (_ratings==null)
			getRatings();
		for (RatingTuple rating : _ratings){
			if (rating.get_movie().equals(movie))
				return true;
		}
		return false;
	}

	public void setDefaultRecs() {
		if (_ratings==null)
			getRatings();
		Collection<MovieTuple> tmp = SystemData.getInstance().getAllMovies();
		MovieTuple[] movies = tmp.toArray(new MovieTuple[tmp.size()]);
		Arrays.sort(movies, new MovieDefaltComparator());
		MovieComputedRating[] ans = new MovieComputedRating[movies.length - _ratings.size()];
		int i=0;
		for (MovieTuple movie : movies){
			if (!hasSeenMovie(movie)){
				ans[i] = new MovieComputedRating(movie.get_name(),movie.get_rating());
				i++;
			}
		}
		_moviesRecomended = ans;

	}
/**
 * this method is only to be used by SystemData
 * @param bdate
 * @param sex
 * 
 */ 	
	public void editUser(String bdate, boolean sex){
		_bdate=bdate;
		/*if (sex.equals("true"))
			_sex=true;
		else _sex=false;*/
	}
	/**
	 * this method is only to be used by SystemData
	 * @param pass
	 */
	public void changePassword (String pass){
		_password=pass;
	}
	
	
	


}
